package com.anuo.app.study.studyjava;

import com.anuo.app.modules.study.entity.Product;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;

/**
 * Java异常处理
 * 研究状态: 全部已完成
 *
 * @ Java 异常分为两大类
 * 1. Error是错误，java.lang.Error : 是Java 内部的严重错误, 比如虚拟机错误啊什么的, 程序员不应该去捕获
 * 2. Exception是异常，java.lang.Exception
 *      包含下面两种(下面两种都继承自 java.lang.Exception):
 *      #Checked异常(检查异常) : java 语言规范, 不处理就无法编译通过, 常见的有 java.io.IOException
*       #RuntimeException : 由java 自己捕获处理, 一般程序员不用处理, 常见的有 Java.lang.NullPointerException
 * @ Throwable是所有异常的根, 上面两个都继承他
 * @ throws : 向上抛异常 或者 如果是checked异常 在方法体内没有try catch , 在方法签名尾部需要加 throws , 多个的话用逗号隔开
 * @ throw : 显式抛出一个异常 , 一般这样写: throw new RuntimeException("hehe") 抛个具体类别的异常可以这样写: throw new  RemoteException();
 * @ 自定义异常: 如果是 checked异常 继承 Exception , 如果是运行时异常 继承 RuntimeException , 参考: http://www.runoob.com/java/java-exceptions.html  搜索: 声明自定义异常
 * @ java异常堆栈倒着看
 * @ try-catch嵌套调用的情况
 */
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations = {"classpath:spring/spring-context.xml"})
public class StudyException {
    public static void main(String[] args) {
        try {
            CheckedException();
            throw new RuntimeException("hehe");//显式抛出异常
        } catch (Exception e) {
            System.out.println("toString :" + e.toString());//用于常见的日志记录 log.info(e.toString())
            System.out.println("getMessage :" + e.getMessage());//获取简要异常信息
            System.out.println("getStackTraceAsString :" + ExceptionUtils.getStackTrace(e)); //获取详细堆栈异常信息
        }
    }

    //2. Exception 中的 Checked 异常
    public static void CheckedException() {
        int[] array = {1, 2};
        int a = array[3];
    }

    /**
     * try-catch嵌套调用的情况
     * 嵌套后:
     * 如果子方法的try-catch 处理了异常, 那么父类就不会再处理
     * 如果子方法的try-catch 没处理异常,并向上抛出来 throw ex, 那么父类就会抓到并处理
     */
    @Test
    public void nestTryCatch() {
        try {
            getName();
        } catch (Exception ex) {
            System.out.println("getName exception");
        }
    }

    private void getName(){
        try {
            List<Product> list = null;
            list.get(0).getPrice();
        } catch (Exception ex) {
            throw ex;
        }
    }



private static class StudyExceptionStacktrace {
    private void fun1() throws IOException {
        throw new IOException("level 1 exception");
    }

    private void fun2() {
        try {
            fun1();
        } catch (IOException e) {
            throw new RuntimeException("level 2 exception", e);
        }
    }

    /**
     * java异常堆栈倒着看
     * 解释: java的异常最先打印的在最下面, 从下面往上倒着看, 下面的错误引起上面的错误
     * 方法的调用顺序也是从下往上看
     *
     * @param args
     */
    public static void main(String[] args) {
        try {
            new StudyExceptionStacktrace().fun2();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
}

